<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Spring AI + Ollama 流式聊天</title>
    <!-- Markdown渲染库 -->
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
    <!-- 代码高亮库 -->
    <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css" rel="stylesheet">
    <style>
        * {
            margin: 0;,
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        .container {
            background: white;
            border-radius: 20px;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
            padding: 30px;
            width: 90%;
            max-width: 900px;
        }

        .header {
            text-align: center;
            margin-bottom: 30px;
        }

        .header h1 {
            color: #333;
            margin-bottom: 10px;
        }

        .header p {
            color: #666;
            font-size: 14px;
        }

        .chat-container {
            border: 1px solid #e0e0e0;
            border-radius: 10px;
            height: 500px;
            overflow-y: auto;
            padding: 20px;
            margin-bottom: 20px;
            background: #f9f9f9;
        }

        .message {
            margin-bottom: 15px;
            padding: 10px 15px;
            border-radius: 10px;
            max-width: 80%;
            word-wrap: break-word;
        }

        .user-message {
            background: #007bff;
            color: white;
            margin-left: auto;
            text-align: right;
        }

        .bot-message {
            background: #e9ecef;
            color: #333;
            margin-right: auto;
        }

        .think-content {
            background: #f8f9fa;
            border-left: 4px solid #6c757d;
            padding: 12px;
            margin: 10px 0;
            font-style: italic;
            color: #6c757d;
            border-radius: 8px;
            font-size: 13px;
            line-height: 1.5;
            border: 1px solid #e9ecef;
        }

        .think-content::before {
            content: "🤔 AI思考过程：";
            font-weight: bold;
            display: block;
            margin-bottom: 8px;
            color: #495057;
            font-style: normal;
        }

        .answer-content {
            background: #e7f3ff;
            border-left: 4px solid #007bff;
            padding: 15px;
            margin: 10px 0;
            color: #333;
            border-radius: 8px;
            line-height: 1.6;
            border: 1px solid #b3d9ff;
        }

        .answer-content::before {
            content: "💡 AI回答：";
            font-weight: bold;
            display: block;
            margin-bottom: 10px;
            color: #007bff;
        }

        .streaming-think {
            background: #fff9e6;
            border-left: 4px solid #ffc107;
            padding: 12px;
            margin: 10px 0;
            font-style: italic;
            color: #856404;
            border-radius: 8px;
            font-size: 13px;
            line-height: 1.5;
            border: 1px solid #ffeaa7;
            position: relative;
        }

        .streaming-think::before {
            content: "🤔 AI思考中...";
            font-weight: bold;
            display: block;
            margin-bottom: 8px;
            color: #b8860b;
            font-style: normal;
        }

        .streaming-think::after {
            content: '●';
            animation: blink 1s infinite;
            margin-left: 5px;
            color: #ffc107;
        }

        .streaming-answer {
            background: #e7f3ff;
            border-left: 4px solid #007bff;
            padding: 15px;
            margin: 10px 0;
            color: #333;
            border-radius: 8px;
            line-height: 1.6;
            border: 1px solid #b3d9ff;
            position: relative;
        }

        .streaming-answer::before {
            content: "💡 AI回答中...";
            font-weight: bold;
            display: block;
            margin-bottom: 10px;
            color: #007bff;
        }

        .streaming-answer::after {
            content: '●';
            animation: blink 1s infinite;
            margin-left: 5px;
            color: #007bff;
        }

        .streaming-message {
            background: #fff3cd;
            border: 1px solid #ffeaa7;
            color: #856404;
            margin-right: auto;
            position: relative;
        }

        .streaming-message::after {
            content: '●';
            animation: blink 1s infinite;
            margin-left: 5px;
        }

        @keyframes blink {
            0%, 50% { opacity: 1; }
            51%, 100% { opacity: 0; }
        }

        .system-message-container {
            margin-bottom: 20px;
        }

        .system-message-container label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
            color: #333;
        }

        .system-message-container select {
            width: 100%;
            padding: 10px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 14px;
            background: white;
            cursor: pointer;
            transition: all 0.3s ease;
        }

        .system-message-container select:focus {
            outline: none;
            border: 2px solid #667eea;
        }

        .system-message-container textarea {
            width: 100%;
            padding: 10px;
            border: 2px solid #ddd;
            border-radius: 8px;
            resize: vertical;
            min-height: 60px;
            font-size: 14px;
            transition: all 0.3s ease;
        }

        .system-message-container textarea:focus {
            outline: none;
            border: 2px solid #667eea;
        }

        .input-container {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
        }

        .input-container input {
            flex: 1;
            padding: 12px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 16px;
            position: relative;
            background: white;
            transition: all 0.3s ease;
        }

        .input-container input:focus {
            outline: none;
            border: 2px solid transparent;
            background: linear-gradient(white, white) padding-box,
                        linear-gradient(135deg, 
                            #FF6B9D 0%, 
                            #C239B3 16.66%, 
                            #7A5FFF 33.33%, 
                            #0A84FF 50%, 
                            #30D158 66.66%, 
                            #FFD60A 83.33%,
                            #FF6B9D 100%
                        ) border-box;
            background-size: 300% 300%;
            animation: borderFlow 2s linear infinite;
        }

        .input-container button {
            padding: 12px 24px;
            /* 默认状态：紫色到蓝色渐变 */
            background: linear-gradient(90deg, #8B5CF6, #3B82F6);
            color: white;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 600;
            position: relative;
            transition: all 0.2s ease;
            box-shadow: 0 4px 14px 0 rgba(139, 92, 246, 0.25);
        }

        .input-container button:hover:not(:disabled) {
            /* 悬停状态：更亮的紫色到蓝色渐变 */
            background: linear-gradient(90deg, #9c75ff, #4d91ff);
            box-shadow: 0 6px 20px 0 rgba(156, 117, 255, 0.35);
            transform: translateY(-1px);
        }

        .input-container button:active:not(:disabled) {
            /* 点击/激活状态：向下移动模拟按下效果 */
            transform: translateY(1px);
            box-shadow: 0 2px 8px 0 rgba(139, 92, 246, 0.25);
        }

        .input-container button.ai-processing {
            /* 加载状态：保持原色但添加脉冲动画 */
            background: linear-gradient(90deg, #8B5CF6, #3B82F6);
            animation: loadingPulse 1.5s ease-in-out infinite;
            cursor: not-allowed;
            transform: none;
            position: relative;
        }

        .input-container button.ai-processing::before {
            content: '';
            display: inline-block;
            width: 16px;
            height: 16px;
            margin-right: 8px;
            border: 2px solid rgba(255, 255, 255, 0.3);
            border-top: 2px solid white;
            border-radius: 50%;
            animation: spin 1s linear infinite;
            vertical-align: middle;
        }

        @keyframes loadingPulse {
            0% {
                opacity: 1;
                transform: scale(1);
            }
            50% {
                opacity: 0.8;
                transform: scale(1.02);
            }
            100% {
                opacity: 1;
                transform: scale(1);
            }
        }

        @keyframes spin {
            0% {
                transform: rotate(0deg);
            }
            100% {
                transform: rotate(360deg);
            }
        }

        @keyframes borderFlow {
            0% {
                background-position: 0% 50%;
            }
            50% {
                background-position: 100% 50%;
            }
            100% {
                background-position: 200% 50%;
            }
        }

        @keyframes gradientFlow {
            0% {
                background-position: 0% 50%;
            }
            50% {
                background-position: 100% 50%;
            }
            100% {
                background-position: 0% 50%;
            }
        }

        .input-container button:disabled {
            background: #ccc !important;
            cursor: not-allowed;
            animation: none !important;
            transform: none !important;
            opacity: 0.6 !important;
        }

        .controls {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
            justify-content: center;
        }

        .controls button {
            padding: 8px 16px;
            border: 1px solid #ddd;
            border-radius: 5px;
            background: white;
            cursor: pointer;
            transition: all 0.3s;
        }

        .controls button:hover {
            background: #f8f9fa;
        }

        .controls button.active {
            background: #007bff;
            color: white;
            border-color: #007bff;
        }

        .status {
            text-align: center;
            margin-bottom: 10px;
            font-size: 14px;
            color: #666;
        }

        .error {
            color: #dc3545;
            background: #f8d7da;
            border: 1px solid #f5c6cb;
            padding: 10px;
            border-radius: 5px;
            margin-bottom: 10px;
        }

        .info {
            color: #0c5460;
            background: #d1ecf1;
            border: 1px solid #bee5eb;
            padding: 10px;
            border-radius: 5px;
            margin-bottom: 10px;
        }

        /* Markdown样式 */
        .markdown-content {
            line-height: 1.6;
        }

        .markdown-content h1,
        .markdown-content h2,
        .markdown-content h3,
        .markdown-content h4,
        .markdown-content h5,
        .markdown-content h6 {
            margin: 16px 0 8px 0;
            font-weight: bold;
            color: #333;
        }

        .markdown-content h1 { font-size: 1.5em; border-bottom: 2px solid #eee; padding-bottom: 8px; }
        .markdown-content h2 { font-size: 1.3em; border-bottom: 1px solid #eee; padding-bottom: 6px; }
        .markdown-content h3 { font-size: 1.2em; }
        .markdown-content h4 { font-size: 1.1em; }

        .markdown-content p {
            margin: 8px 0;
        }

        .markdown-content ul,
        .markdown-content ol {
            margin: 8px 0;
            padding-left: 20px;
        }

        .markdown-content li {
            margin: 4px 0;
        }

        .markdown-content blockquote {
            border-left: 4px solid #ddd;
            margin: 8px 0;
            padding: 8px 16px;
            background: #f9f9f9;
            color: #666;
        }

        .markdown-content code {
            background: #f4f4f4;
            padding: 2px 4px;
            border-radius: 3px;
            font-family: 'Courier New', monospace;
            font-size: 0.9em;
        }

        .markdown-content pre {
            background: #f8f8f8;
            border: 1px solid #ddd;
            border-radius: 5px;
            padding: 12px;
            margin: 8px 0;
            overflow-x: auto;
        }

        .markdown-content pre code {
            background: none;
            padding: 0;
        }

        .markdown-content table {
            border-collapse: collapse;
            width: 100%;
            margin: 8px 0;
        }

        .markdown-content th,
        .markdown-content td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }

        .markdown-content th {
            background: #f2f2f2;
            font-weight: bold;
        }

        .markdown-content a {
            color: #007bff;
            text-decoration: none;
        }

        .markdown-content a:hover {
            text-decoration: underline;
        }

        .markdown-content strong {
            font-weight: bold;
        }

        .markdown-content em {
            font-style: italic;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🚀 Spring AI + Ollama 流式聊天</h1>
            <p>体验AI思考过程的实时展现</p>
        </div>

        <div class="status" id="status">
            连接状态: <span id="statusText">准备就绪</span>
        </div>

        <div class="controls">
            <button id="clearChat" onclick="clearChat()">清空对话</button>
            <button onclick="testMarkdown()">测试Markdown</button>
        </div>

        <div class="system-message-container">
            <label for="systemMessage">提示词选择:</label>
            <select id="systemMessage" onchange="handlePromptChange()">
                <option value="">默认模式</option>
                <option value="markdown" selected>Markdown格式回答</option>
                <option value="code">代码专家</option>
                <option value="teacher">教学助手</option>
                <option value="translator">翻译助手</option>
                <option value="custom">自定义...</option>
            </select>
            <textarea id="customPrompt" placeholder="输入自定义提示词..." style="display: none; margin-top: 10px;"></textarea>
        </div>

        <div class="system-message-container">
            <label for="displayMode">通信方式:</label>
            <select id="displayMode">
                <option value="simulate" selected>1. 后端API - 流式输出（推荐）</option>
                <option value="instant">2. 后端API - 立即输出</option>
            </select>
        </div>

        <div class="chat-container" id="chatContainer">
            <div class="message bot-message">
                👋 你好！我是基于Ollama的AI助手。现在支持流式输出，你可以看到我的思考过程！
            </div>
        </div>

        <div class="input-container">
            <input type="text" id="messageInput" placeholder="请输入问题（回答将以Markdown格式展示）..." onkeypress="handleKeyPress(event)">
            <button onclick="sendMessage()" id="sendButton">发送</button>
        </div>
    </div>

    <script>
        const API_BASE = 'http://localhost:8085/api/ollama';
        let currentEventSource = null;
        let currentStreamingMessage = null;
        let currentThinkElement = null;
        let currentAnswerElement = null;
        let isInThinkTag = false;
        let streamBuffer = '';
        let displayInterval = null; // 用于控制逐字符显示的定时器
        let displayQueue = ''; // 待显示的HTML内容队列
        let displayIndex = 0; // 当前显示到的位置

        // 预设提示词
        const PRESET_PROMPTS = {
            'markdown': '你是一个专业的AI助手。请始终使用Markdown格式回答问题，包括使用标题、列表、表格、代码块等格式来组织内容，使答案更清晰易读。',
            'code': '你是一个编程专家。请用Markdown格式回答，代码部分使用代码块（```语言名），并添加详细的注释和说明。',
            'teacher': '你是一个耐心的教学助手。请用Markdown格式回答，使用清晰的结构（标题、列表等）来解释概念，适合初学者理解。',
            'translator': '你是一个专业的翻译助手。请提供准确的翻译，并用Markdown格式展示原文和译文的对照。'
        };

        // 处理提示词选择变化
        function handlePromptChange() {
            const select = document.getElementById('systemMessage');
            const customPrompt = document.getElementById('customPrompt');
            
            if (select.value === 'custom') {
                customPrompt.style.display = 'block';
                customPrompt.focus();
            } else {
                customPrompt.style.display = 'none';
            }
        }

        // 获取当前系统提示词
        function getCurrentSystemPrompt() {
            const select = document.getElementById('systemMessage');
            const customPrompt = document.getElementById('customPrompt');
            
            if (select.value === 'custom') {
                return customPrompt.value.trim();
            } else if (select.value) {
                return PRESET_PROMPTS[select.value] || '';
            }
            return '';
        }

        // 配置Marked.js
        if (typeof marked !== 'undefined') {
            marked.setOptions({
                highlight: function(code, lang) {
                    if (typeof Prism !== 'undefined' && lang && Prism.languages[lang]) {
                        return Prism.highlight(code, Prism.languages[lang], lang);
                    }
                    return code;
                },
                breaks: false, // 改为false，避免单个换行符破坏表格
                gfm: true,
                tables: true, // 明确启用表格支持
                pedantic: false
            });
        }

        // 渲染Markdown内容
        function renderMarkdown(content) {
            if (typeof marked !== 'undefined') {
                const html = marked.parse(content);
                console.log('Markdown原始内容（前200字符）:', content.substring(0, 200));
                console.log('渲染后HTML（前500字符）:', html.substring(0, 500));
                console.log('是否包含<table>标签:', html.includes('<table>'));
                return html;
            }
            return content.replace(/\n/g, '<br>');
        }

        // 安全地设置HTML内容
        function setElementContent(element, content, isMarkdown = true) {
            if (isMarkdown) {
                const htmlContent = renderMarkdown(content);
                element.innerHTML = htmlContent;
                element.classList.add('markdown-content');
                // 触发代码高亮
                if (typeof Prism !== 'undefined') {
                    Prism.highlightAllUnder(element);
                }
            } else {
                element.textContent = content;
            }
        }

        // 模拟流式显示HTML内容（逐字符显示）
        function simulateStreamDisplay(element, htmlContent) {
            // 清除之前的定时器
            if (displayInterval) {
                clearInterval(displayInterval);
            }
            
            displayQueue = htmlContent;
            displayIndex = 0;
            element.innerHTML = '';
            element.classList.add('markdown-content');
            
            // 每10毫秒显示一部分内容
            displayInterval = setInterval(() => {
                if (displayIndex < displayQueue.length) {
                    // 每次显示5个字符，加快显示速度
                    const chunk = displayQueue.substring(0, displayIndex + 5);
                    displayIndex += 5;
                    element.innerHTML = chunk;
                    
                    // 滚动到底部
                    const chatContainer = document.getElementById('chatContainer');
                    chatContainer.scrollTop = chatContainer.scrollHeight;
                } else {
                    // 显示完成
                    clearInterval(displayInterval);
                    displayInterval = null;
                    element.innerHTML = displayQueue;
                    
                    // 触发代码高亮
                    if (typeof Prism !== 'undefined') {
                        Prism.highlightAllUnder(element);
                    }
                }
            }, 10);
        }


        // 更新状态
        function updateStatus(message, isError = false) {
            const statusText = document.getElementById('statusText');
            statusText.textContent = message;
            statusText.style.color = isError ? 'red' : 'green';
        }

        // 添加消息到聊天容器
        function addMessage(message, isUser = false, isStreaming = false) {
            const chatContainer = document.getElementById('chatContainer');
            const messageDiv = document.createElement('div');
            
            if (isStreaming) {
                messageDiv.className = 'message streaming-message';
                currentStreamingMessage = messageDiv;
            } else {
                messageDiv.className = `message ${isUser ? 'user-message' : 'bot-message'}`;
            }
            
            // 对于用户消息使用纯文本，对于AI消息使用Markdown渲染
            if (isUser || isStreaming) {
                messageDiv.textContent = message;
            } else {
                setElementContent(messageDiv, message, true);
            }
            chatContainer.appendChild(messageDiv);
            chatContainer.scrollTop = chatContainer.scrollHeight;
            return messageDiv;
        }

        // 创建流式思考容器
        function createStreamingThinkContainer() {
            const chatContainer = document.getElementById('chatContainer');
            const thinkDiv = document.createElement('div');
            thinkDiv.className = 'streaming-think';
            chatContainer.appendChild(thinkDiv);
            chatContainer.scrollTop = chatContainer.scrollHeight;
            currentThinkElement = thinkDiv;
            return thinkDiv;
        }

        // 创建流式答案容器
        function createStreamingAnswerContainer() {
            const chatContainer = document.getElementById('chatContainer');
            const answerDiv = document.createElement('div');
            answerDiv.className = 'streaming-answer';
            chatContainer.appendChild(answerDiv);
            chatContainer.scrollTop = chatContainer.scrollHeight;
            currentAnswerElement = answerDiv;
            return answerDiv;
        }

        // 解析并处理流式内容
        function processStreamContent(content) {
            streamBuffer += content;
            
            // 检查是否包含 <think> 标签
            const thinkStartMatch = streamBuffer.match(/<think>/i);
            const thinkEndMatch = streamBuffer.match(/<\/think>/i);
            
            if (thinkStartMatch && !isInThinkTag) {
                // 开始思考过程
                isInThinkTag = true;
                if (!currentThinkElement) {
                    createStreamingThinkContainer();
                }
                // 移除 <think> 标签并保留后面的内容
                streamBuffer = streamBuffer.substring(thinkStartMatch.index + thinkStartMatch[0].length);
            }
            
            if (thinkEndMatch && isInThinkTag) {
                // 结束思考过程
                const thinkContent = streamBuffer.substring(0, thinkEndMatch.index);
                if (currentThinkElement && thinkContent.trim()) {
                    currentThinkElement.textContent = thinkContent.trim();
                    // 完成思考部分，改变样式
                    currentThinkElement.className = 'think-content';
                }
                
                isInThinkTag = false;
                currentThinkElement = null;
                
                // 保留 </think> 标签后面的内容作为答案开始
                streamBuffer = streamBuffer.substring(thinkEndMatch.index + thinkEndMatch[0].length);
                
                // 创建答案容器
                if (streamBuffer.length > 0 || !thinkEndMatch) {
                    createStreamingAnswerContainer();
                }
            }
            
            // 更新当前显示的内容
            if (isInThinkTag && currentThinkElement) {
                // 在思考过程中，使用纯文本实时显示
                currentThinkElement.textContent = streamBuffer;
            } else if (!isInThinkTag && currentAnswerElement) {
                // 在答案流式过程中，实时渲染Markdown并显示
                const htmlContent = renderMarkdown(streamBuffer);
                currentAnswerElement.innerHTML = htmlContent;
                currentAnswerElement.classList.add('markdown-content');
                // 触发代码高亮
                if (typeof Prism !== 'undefined') {
                    Prism.highlightAllUnder(currentAnswerElement);
                }
            } else if (!isInThinkTag && !currentAnswerElement && streamBuffer.length > 0) {
                // 没有思考过程，直接是答案
                createStreamingAnswerContainer();
                // 实时渲染Markdown并显示
                const htmlContent = renderMarkdown(streamBuffer);
                currentAnswerElement.innerHTML = htmlContent;
                currentAnswerElement.classList.add('markdown-content');
                // 触发代码高亮
                if (typeof Prism !== 'undefined') {
                    Prism.highlightAllUnder(currentAnswerElement);
                }
            }
            
            // 滚动到底部
            const chatContainer = document.getElementById('chatContainer');
            chatContainer.scrollTop = chatContainer.scrollHeight;
        }

        // 更新流式消息
        function updateStreamingMessage(content) {
            if (currentStreamingMessage) {
                currentStreamingMessage.textContent = content;
                document.getElementById('chatContainer').scrollTop = document.getElementById('chatContainer').scrollHeight;
            }
        }

        // 完成流式消息
        function completeStreamingMessage() {
            if (currentStreamingMessage) {
                currentStreamingMessage.className = 'message bot-message';
                currentStreamingMessage = null;
            }
            
            // 完成思考部分
            if (currentThinkElement) {
                currentThinkElement.className = 'think-content';
                // 思考内容保持纯文本
                currentThinkElement = null;
            }
            
            // 完成答案部分
            if (currentAnswerElement) {
                // 更改样式类为完成状态
                currentAnswerElement.className = 'answer-content markdown-content';
                // 内容已经在流式过程中实时渲染了，这里只需要改变样式
                currentAnswerElement = null;
            }
            
            // 重置状态
            isInThinkTag = false;
            streamBuffer = '';
            
            // 恢复发送按钮状态
            const sendButton = document.getElementById('sendButton');
            sendButton.disabled = false;
            sendButton.classList.remove('ai-processing');
            sendButton.textContent = '发送';
            document.getElementById('messageInput').focus();
        }

        // 显示错误消息
        function showError(message) {
            const chatContainer = document.getElementById('chatContainer');
            const errorDiv = document.createElement('div');
            errorDiv.className = 'error';
            errorDiv.textContent = `❌ 错误: ${message}`;
            chatContainer.appendChild(errorDiv);
            chatContainer.scrollTop = chatContainer.scrollHeight;
        }

        // 显示信息消息
        function showInfo(message) {
            const chatContainer = document.getElementById('chatContainer');
            const infoDiv = document.createElement('div');
            infoDiv.className = 'info';
            infoDiv.textContent = `ℹ️ ${message}`;
            chatContainer.appendChild(infoDiv);
            chatContainer.scrollTop = chatContainer.scrollHeight;
        }


        // 发送非流式消息（一次性获取完整结果）
        function sendNonStreamMessage(message, systemMessage) {
            // 统一使用带系统提示的接口，systemMessage为空时后端会使用默认值
            const url = `${API_BASE}/chat-with-system`;
            
            const requestBody = { 
                prompt: message, 
                systemMessage: systemMessage || '你是一个专业的AI助手，请用清晰、简洁的语言回答问题。'
            };

            // 显示加载状态
            const loadingMessage = addMessage('正在等待AI回答...', false, true);
            
            updateStatus('正在请求AI回答...');

            // 使用fetch发送POST请求
            fetch(url, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(requestBody)
            })
            .then(response => {
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                return response.json();
            })
            .then(result => {
                console.log('收到完整响应:', result);
                
                // 检查响应是否成功
                if (!result.success) {
                    throw new Error(result.error || '请求失败');
                }
                
                const data = result.response;
                console.log('响应内容长度:', data.length);
                
                // 解析响应（可能包含<think>标签）
                const thinkMatch = data.match(/<think>([\s\S]*?)<\/think>/i);
                let thinkContent = '';
                let answerContent = data;
                
                if (thinkMatch) {
                    thinkContent = thinkMatch[1].trim();
                    answerContent = data.replace(/<think>[\s\S]*?<\/think>/i, '').trim();
                }
                
                // 清除加载消息
                if (loadingMessage) {
                    loadingMessage.remove();
                }
                
                // 创建新的机器人消息容器
                const messageDiv = document.createElement('div');
                messageDiv.className = 'message bot-message';
                
                // 如果有思考过程，显示思考内容
                if (thinkContent) {
                    const thinkDiv = document.createElement('div');
                    thinkDiv.className = 'think-content';
                    thinkDiv.textContent = thinkContent;
                    messageDiv.appendChild(thinkDiv);
                }
                
                // 显示答案内容
                const answerDiv = document.createElement('div');
                answerDiv.className = 'answer-content';
                
                // 渲染Markdown
                const htmlContent = renderMarkdown(answerContent);
                answerDiv.innerHTML = htmlContent;
                answerDiv.classList.add('markdown-content');
                
                // 触发代码高亮
                if (typeof Prism !== 'undefined') {
                    Prism.highlightAllUnder(answerDiv);
                }
                
                messageDiv.appendChild(answerDiv);
                document.getElementById('chatContainer').appendChild(messageDiv);
                
                // 滚动到底部
                const chatContainer = document.getElementById('chatContainer');
                chatContainer.scrollTop = chatContainer.scrollHeight;
                
                updateStatus('回答完成');
                
                // 恢复发送按钮
                const sendButton = document.getElementById('sendButton');
                sendButton.disabled = false;
                sendButton.classList.remove('ai-processing');
                sendButton.textContent = '发送';
                document.getElementById('messageInput').focus();
            })
            .catch(error => {
                console.error('请求失败:', error);
                showError(`请求失败: ${error.message}`);
                
                // 恢复发送按钮
                const sendButton = document.getElementById('sendButton');
                sendButton.disabled = false;
                sendButton.classList.remove('ai-processing');
                sendButton.textContent = '发送';
            });
        }

        // 发送流式消息
        function sendStreamMessage(message, systemMessage) {
            // 统一使用带系统提示的流式接口，systemMessage为空时后端会使用默认值
            const url = `${API_BASE}/chat-with-system-stream`;
            
            const requestBody = { 
                prompt: message, 
                systemMessage: systemMessage || '你是一个专业的AI助手，请用清晰、简洁的语言回答问题。'
            };

            // 立即显示"AI思考中"提示
            const loadingMessage = addMessage('🤔 AI思考中，正在生成回答...', false, true);
            
            // 使用fetch发送POST请求启动流式响应
            fetch(url, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(requestBody)
            }).then(response => {
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                
                // 移除加载提示
                if (loadingMessage) {
                    loadingMessage.remove();
                }
                
                updateStatus('开始接收流式响应...');
                // 重置流式状态
                currentThinkElement = null;
                currentAnswerElement = null;
                isInThinkTag = false;
                streamBuffer = '';
                
                const reader = response.body.getReader();
                const decoder = new TextDecoder();
                let buffer = '';

                function readStream() {
                    reader.read().then(({ done, value }) => {
                        if (done) {
                            completeStreamingMessage();
                            updateStatus('流式响应完成');
                            return;
                        }

                        buffer += decoder.decode(value, { stream: true });
                        const lines = buffer.split('\n');
                        buffer = lines.pop(); // 保留不完整的行

                        for (const line of lines) {
                            if (line.startsWith('data:')) {
                                const data = line.slice(5); // 移除 'data:' (5个字符)，保留空白字符
                                console.log('接收到SSE数据:', JSON.stringify(data)); // 调试日志
                                
                                // 检查是否是结束信号
                                if (data.trim() === '流式响应完成' || data.trim() === '[DONE]') {
                                    completeStreamingMessage();
                                    updateStatus('流式响应完成');
                                    return;
                                }
                                
                                // 检查是否是错误信号
                                if (line.includes('event: error')) {
                                    showError(data);
                                    completeStreamingMessage();
                                    return;
                                }
                                
                                // 正常的消息数据，使用新的解析函数处理
                                // 空字符串代表换行符，需要添加到streamBuffer
                                if (data.length === 0) {
                                    processStreamContent('\n');
                                } else {
                                    processStreamContent(data);
                                }
                            } else if (line.startsWith('event:')) {
                                // 事件类型处理
                            } else if (line.trim() === '') {
                                // 空行，SSE消息结束
                            }
                        }

                        readStream();
                    }).catch(error => {
                        console.error('读取流式响应失败:', error);
                        showError(`流式响应错误: ${error.message}`);
                        completeStreamingMessage();
                    });
                }

                readStream();
            }).catch(error => {
                console.error('启动流式请求失败:', error);
                // 移除加载提示
                if (loadingMessage) {
                    loadingMessage.remove();
                }
                showError(`启动流式请求失败: ${error.message}`);
                // 恢复发送按钮状态
                const sendButton = document.getElementById('sendButton');
                sendButton.disabled = false;
                sendButton.classList.remove('ai-processing');
                sendButton.textContent = '发送';
            });
        }

        // 发送消息
        function sendMessage() {
            const messageInput = document.getElementById('messageInput');
            const systemMessage = getCurrentSystemPrompt();
            const message = messageInput.value.trim();
            
            if (!message) {
                alert('请输入问题！');
                return;
            }

            // 添加用户消息
            addMessage(message, true);
            messageInput.value = '';

            // 禁用发送按钮并添加AI处理样式
            const sendButton = document.getElementById('sendButton');
            sendButton.disabled = true;
            sendButton.classList.add('ai-processing');
            sendButton.textContent = 'AI思考中';
            updateStatus('正在处理...');

            // 根据显示模式选择调用流式或非流式接口
            const displayMode = document.getElementById('displayMode').value;
            if (displayMode === 'instant') {
                // 立即显示模式：调用非流式接口
                sendNonStreamMessage(message, systemMessage);
            } else {
                // 模拟流式显示模式：调用流式接口
                sendStreamMessage(message, systemMessage);
            }
        }

        // 清空对话
        function clearChat() {
            // 清除模拟显示定时器
            if (displayInterval) {
                clearInterval(displayInterval);
                displayInterval = null;
            }
            
            const chatContainer = document.getElementById('chatContainer');
            chatContainer.innerHTML = `
                <div class="message bot-message">
                    👋 对话已清空！我是基于Ollama的AI助手，有什么可以帮助你的吗？
                </div>
            `;
            // 重置所有流式状态
            currentStreamingMessage = null;
            currentThinkElement = null;
            currentAnswerElement = null;
            isInThinkTag = false;
            streamBuffer = '';
            displayQueue = '';
            displayIndex = 0;
            updateStatus('对话已清空');
        }

        // 处理回车键
        function handleKeyPress(event) {
            if (event.key === 'Enter' && !event.shiftKey) {
                event.preventDefault();
                sendMessage();
            }
        }

        // 测试Markdown渲染
        function testMarkdown() {
            const testContent = `# Markdown测试

## 基本格式
这是一个**粗体**文本和*斜体*文本的示例。

## 代码示例
这是行内代码：\`console.log('Hello World')\`

代码块示例：
\`\`\`javascript
function greet(name) {
    return \`Hello, \${name}!\`;
}

console.log(greet('AI助手'));
\`\`\`

## 列表
### 无序列表
- 项目1
- 项目2
  - 子项目2.1
  - 子项目2.2
- 项目3

### 有序列表
1. 第一步
2. 第二步
3. 第三步

## 表格
| 功能 | 状态 | 描述 |
|------|------|------|
| Markdown渲染 | ✅ | 支持基本语法 |
| 代码高亮 | ✅ | 使用Prism.js |
| 流式输出 | ✅ | 实时渲染 |

## 引用
> 这是一个引用块的示例。
> 可以包含多行内容。

## 链接
访问 [GitHub](https://github.com) 了解更多信息。`;

            addMessage(testContent, false, false);
            updateStatus('Markdown测试完成');
        }
        
        // 页面加载完成
        window.onload = function() {
            document.getElementById('messageInput').focus();
            updateStatus('准备就绪 - 流式模式');
        };
        
        // 页面卸载时关闭连接
        window.onbeforeunload = function() {
            if (currentEventSource) {
                currentEventSource.close();
            }
        };
    </script>
</body>
</html>
